#pragma once

#include <iostream>
#include <string>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
 #include <unistd.h>

#include"Log.hpp"
#include"Task.hpp"
#include"ThreadPool.hpp"

using namespace std;

const int defalutfd = -1;
const string defalutip = "0.0.0.0";
const int backlog = 10;

enum
{
    UseageError = 1,
    SocketError,
    BindError,
    ListenError
};

class ThreadData
{
public:
    ThreadData(int fd, const string& ip, const uint16_t& port, Tcpserver* t)
        :sockfd(fd)
        ,clientip(ip)
        ,clientport(port)
        ,tsvr(t)
    {}
public:
    int sockfd;
    string clientip;
    uint16_t clientport;
    Tcpserver* tsvr;
};

class Tcpserver
{
public:
    Tcpserver(const uint16_t& port, const string& ip = defalutip)
            :Listensock_(defalutfd)
            ,port_(port)
            ,ip_(ip)
    {}

    void Init()
    {
        Listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if(Listensock_ < 0)
        {
            log(Fatal, "socket error, error is:%d, error string is: %s", errno, strerror(errno));
            exit(SocketError);
        }
        log(Info, "socket success,  Listensock is:%d", Listensock_);

        int opt = 1;
        setsockopt(Listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());

        if(bind(Listensock_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log(Fatal, "bind error, error is:%d, error string is: %s", errno, strerror(errno));
            exit(BindError);
        }
        log(Info, "bind success,  Listensock is:%d", Listensock_);

        if(listen(Listensock_, backlog) < 0)
        {
            log(Fatal, "listen error, error is:%d, error string is: %s", errno, strerror(errno));
            exit(ListenError);
        }
        log(Info, "listen success,  Listensock is:%d", Listensock_);
    }

    void start()
    {
        ThreadPool<Task>::GetInstance()->Start();

        while(true)
        {
            //获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(Listensock_, (struct sockaddr *)&client, &len);
            if(sockfd < 0)
            {
                log(Warning, "accept error, error is:%d, error string is: %s", errno, strerror(errno));
                continue;
            }
            //网络序变字节序;
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
        
           //新连接进行通信;
           log(Info, "get a new link... sockfd: %d, client ip is %s, client port is %d ", Listensock_, clientip, clientport);
           Task t(sockfd, clientip, clientport);
           ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    void service(int sockfd, const string& clientip, const uint16_t& clientport)
    {
        char buffer[1024];
        while(true)
        {
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if(n > 0)
            {
                buffer[n] = 0;
                cout << "client say# " << buffer << endl;
                string echo_string = "tcpserver echo# ";
                echo_string += buffer;

                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if(n ==  0)
            {
                log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport);
                break;
            }
            else
            {
                log(Info, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }

    ~Tcpserver()
    {}
private:
    int Listensock_;
    uint16_t port_;
    string ip_;
};